package com.xbongbong.sso.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.URLEncodeUtils;
import com.xbongbong.paas.toolbox.wrap.XbbResponse;
import com.xbongbong.pro.constant.XbbProConstant;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.sso.pojo.dto.GetOauthConnectorDTO;
import com.xbongbong.sso.pojo.dto.UserOauthDTO;
import com.xbongbong.sso.pojo.vo.GetOauthConnectorVO;
import com.xbongbong.sso.pojo.vo.OauthFlowVO;
import com.xbongbong.sso.pojo.vo.UserOauthVO;
import com.xbongbong.sso.service.OauthFlowService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Objects;

/**
 * sso登录过程
 * 创建时间 2020/12/28 2:51 PM
 * 修改时间 2020/12/28 2:51 PM
 * @author chy
 */
@RestController
@RequestMapping(XbbProConstant.API_ROOT_PREFIX + "/sso")
public class OauthFlowController {

    private static final Logger LOG = LoggerFactory.getLogger(OauthFlowController.class);

    @Resource
    private OauthFlowService oauthFlowService;

    /**
     * 跳转到登录地址后，获取授权连接器，用于后续三方登录
     * @param getOauthConnectorDTO 关联DTO
     */
    @RequestMapping(value = "/getOauthConnector", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String getOauthConnector(@RequestBody @Valid GetOauthConnectorDTO getOauthConnectorDTO, BindingResult br) throws Exception{
        XbbResponse<GetOauthConnectorVO> response = null;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            try {
                GetOauthConnectorVO getOauthConnectorVO = oauthFlowService.getOauthConnector(getOauthConnectorDTO);
                response = new XbbResponse<>(getOauthConnectorVO);
            } catch (XbbException e) {
                response = new XbbResponse<>(e);
            }
        }
        return JSON.toJSONString(response);
    }


    /**
     * 根据设置，获取用户授权开始步骤
     * 1、如果设置了Auth Code步骤，返回header、带参数的url
     * 2、如果没有设置Auth Code步骤，不需要用户授权，在后台依次走完步骤，生成登录链接
     * @param userOauthDTO 关联DTO
     */
    @RequestMapping(value = "/userOauth", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String userOauth(@RequestBody @Valid UserOauthDTO userOauthDTO, BindingResult br) throws Exception{
        XbbResponse<UserOauthVO> response = null;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            try {
                UserOauthVO userOauthVO = oauthFlowService.userOauth(userOauthDTO);
                response = new XbbResponse<>(userOauthVO);
            } catch (XbbException e) {
                response = new XbbResponse<>(e);
            }
        }
        return JSON.toJSONString(response);
    }

    @RequestMapping(value = "/{sign}/code", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public void code(@PathVariable("sign") String sign, HttpServletRequest request, HttpServletResponse response) throws IOException {
        JSONObject jsonObject = getParameter(request);
        try {
            OauthFlowVO oauthFlowVO = oauthFlowService.oauthFlow(sign, jsonObject);
            response.sendRedirect(oauthFlowVO.getLoginUrl());
        } catch (XbbException e) {
            String ssoLoginUrl;
            try {
                ssoLoginUrl = oauthFlowService.getRedirectLoginUrl(sign);
            } catch (XbbException ex) {
                throw new RuntimeException(ex);
            }
            ssoLoginUrl = ssoLoginUrl + "&errorMsg=" + URLEncodeUtils.encodeURL(e.getMsg());
            response.sendRedirect(ssoLoginUrl);
        }
    }

    private JSONObject getParameter(HttpServletRequest request) {
        JSONObject json = new JSONObject();
        //获取所有参数名
        Enumeration e = request.getParameterNames();
        //通过Enumeration类中的hasMoreElements()判断是否还有参数名
        while(e.hasMoreElements()){
            //获取当前参数名
            String parameterName = (String)e.nextElement();
            json.put(parameterName, request.getParameter(parameterName));
        }
        return json;
    }

    @RequestMapping(value = "/{sign}/login", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public void login(@PathVariable("sign") String sign, HttpServletResponse resp) throws IOException {
        String ssoLoginUrl = null;
        try {
            ssoLoginUrl = oauthFlowService.getRedirectLoginUrl(sign);
        } catch (XbbException e) {
            throw new RuntimeException(e);
        }
        resp.sendRedirect(ssoLoginUrl);
    }

    /**
     * 前端接收到IDP返回的授权码等相关信息时，通过post返回给服务端
     * @param connectorSign
     * @param jsonObject
     * @return
     */
    @RequestMapping(value = "/{connectorSign}/oauthFlow", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String oauthFlow(@PathVariable("connectorSign") String connectorSign, @RequestBody JSONObject jsonObject) {
        XbbResponse<OauthFlowVO> response = null;
        try {
            OauthFlowVO oauthFlowVO = oauthFlowService.oauthFlow(connectorSign, jsonObject);
            response = new XbbResponse<>(oauthFlowVO);
        } catch (XbbException e) {
            response = new XbbResponse<>(e);
        }
        return JSON.toJSONString(response);
    }
}
